

#include "unity.h"
#include "unity_fixture.h"
#include <string.h>
#include "Log.h"
#include "BSP.h"
#include "BSP_Sleep.h"
#include <Utility/BitReverse.h>
#include "rfid_common.h"
#include "HIDProx.h"

void rfid_itf_clr_tag(uint8_t tag);
void rfid_itf_set_tag(uint8_t tag);

/*
判断卡类型，3block或6block
3block：直接解析
6block：与之前缓存的数据对比，一样，则开始解析；否则，先缓存。
解析完成后，清除缓存。
*/


#if 0
/*------------------------------------------------------*/

static void PrintSlider(const char* tag, const BitSlider_T* slider, int dir){
	DBG_WRITE("\n");
	DBG_WRITE(tag);
	DBG_WRITE("\n");
	if(dir){
		uint32_t pos = slider->head;
		while(pos < slider->tail){
			int val = BitBundles_Read(slider->bundles, pos++);
			DBG_PUT_CHAR(val ? '1' : '0');
		}
	}
	else{
		uint32_t pos = slider->tail;
		while(pos > slider->head){
			pos--;
			int val = BitBundles_Read(slider->bundles, pos);
			DBG_PUT_CHAR(val ? '1' : '0');
		}
	}
	DBG_WRITE("\n");
}

static void HIDCard_Frame_Init(HidFrame_T* frame){
	BitSlider_Init(&frame->bits, frame->container, sizeof(frame->container)/sizeof(frame->container[0]), 0);
	frame->type = HID_FRAME_None;
	memset(frame->container, 0, sizeof(frame->container));
}

static int HIDCard_Frame_Compare(const HidFrame_T* frame1, const HidFrame_T* frame2){
	if(frame1->type != frame2->type){
		return 1;
	}
	uint32_t len1 = BitSlider_Length(&frame1->bits);
	uint32_t len2 = BitSlider_Length(&frame2->bits);
	if(len1 != len2){
		return 2;
	}
	const uint32_t byteCount = len1 / sizeof(uint8_t);
	const uint8_t* data1 = (uint8_t*)frame1->container;
	const uint8_t* data2 = (uint8_t*)frame2->container;
	if(memcmp(data1, data2, byteCount)){
		return 3;
	}
	
	return 0;
}

static void HIDCard_Frame_Copy(HidFrame_T* to, HidFrame_T* from){
	*to = *from;
	to->bits.bundles = to->container;
}

static enum HidFrameType HIDCard_CheckFrameType(BitSlider_T* bits){
	if(BitSlider_Length(bits) != (HID_CARD_LONG_FRAME_SIZE - 8)){
		return HID_FRAME_None;
	}
/*
For 3 block tags there will be a header at the begging of the buffer and
again at the 3-block boundary (12 th bytes of the buffer).
*/
	const uint8_t * buf = (uint8_t*)bits->bundles;
	if(buf[11] == HID_CARD_SOF){
		return HID_FRAME_Short;
	}
	
	return HID_FRAME_Long;
}

static int HIDCard_Frame_Build(HidFrame_T* frame, BitSlider_T* bits){
	if(bits->num_bundles <= sizeof(frame->container)/sizeof(uint32_t)){
		frame->bits = *bits;
		frame->bits.bundles = frame->container;
		memcpy(frame->container, bits->bundles, bits->num_bundles * sizeof(uint32_t));
		frame->type = HIDCard_CheckFrameType(bits);
		return 0;
	}
	
	return -1;
}
/*------------------------------------------------------*/
#if 0
static int hid_card_manchester_decode(uint32_t bits, uint32_t size, uint32_t* data){
	uint32_t idx = 0;
	uint32_t d = 0;
	
	if(size < 2 || size & 1){
		TRACE_E("size= %d", size);
		return -1;
	}
	
	*data = 0;
	
	do{
		uint32_t c = (bits >> idx) & 0x03;
		if(c == 0x01){
			//由高到低
			d |= 1;
		}
		else
		if(c == 0x02){
			//由低到高
			//d |= 0;
		}
		else{
			TRACE_E("c=%X", c);
			return -2;
		}
		d <<= 1;
		idx += 2;
	}while(idx < size);
	
	*data = d;
	return 0;
}
#endif 

static int HIDCard_DecodeManchester(HidFrame_T* frame, BitSlider_T* output){
	uint32_t *bundles = frame->bits.bundles;
	uint32_t pos = frame->bits.head;
	uint32_t tail = frame->bits.tail;
	if(frame->type == HID_FRAME_Short){
		tail = frame->bits.tail - HID_CARD_SHORT_FRAME_SIZE;
	}
	uint32_t bits[2];
	uint32_t val;
	BitSlider_Clear(output, BitSlider_MaxLength(output));
	while(pos < tail){
		bits[0] = BitBundles_Read(bundles, pos++);
		bits[1] = BitBundles_Read(bundles, pos++);
		if(bits[0] == 0 && bits[1] == 1){
			//上升沿
			val = 0;
		}
		else
		if(bits[0] == 1 && bits[1] == 0){
			//下降沿
			val = 1;
		}
		else{
			LOG_ERR("Manchester error: %d,%d", bits[0], bits[1]);
			return -1;
		}
		BitSlider_Push(output, val);
	}
	
	return 0;
}

static int HIDCard_PraseData1(BitSlider_T* output){
	uint8_t sentinel = 0;
	
	while(!BitSlider_Remove(output, &sentinel)){
		if(sentinel != 0){
			return 0;
		}
	}
	
	LOGE(NULL, "sentinel NOT found!!");
	return -2;
}


static int HIDCard_GetCustomerCode(BitSlider_T* slider){
	const uint8_t size = 7;
	
	if(BitSlider_Length(slider) < size){
		return -1;
	}
	
	slider->tail -= size;
	uint32_t snap = 0;
	BitBundles_ReadSnap(slider->bundles, slider->tail, &snap, size, 0);
	return snap ;
}

void HIDCard_GetUID(BitSlider_T* output, uint8_t* uid, uint8_t* ulen){
	uint8_t len = 0;
	uint8_t val;
	
	while(BitSlider_PopLSB8(output, &val) > 0){
		uid[len++] = val;
	}
	
	uint8_t size = BitSlider_Length(output);
	if(size){
		output->tail = output->head;
		uint32_t snap = 0;
		BitBundles_ReadSnap(output->bundles, output->tail, &snap, size, 0);
		val = snap;
		uid[len++] = val;
	}
	
	*ulen = len;
}

static int HIDCard_PraseData(BitSlider_T* output){
	int ret = 0;
	int code = HIDCard_GetCustomerCode(output);

	LOGD(NULL, "customer code:%d", code);
	
	switch(code){
	case 0:{
		//Standard HID 37 bit Access Control Cards  
	}
	break;
	case 1:{
		//Standard HID 1-36 bit access control cards
		ret = HIDCard_PraseData1(output);
		if(ret){
			return ret;
		}
	}
	break;
	default:{
		LOGE(NULL, "Not support customer code!");
		return -1;
	}
	}
	PrintSlider("out", output, 0);
	return 0;
}

static int HIDCard_DecodeFrame(HidFrame_T* frame, BitSlider_T* output){
	int ret = HIDCard_DecodeManchester(frame, output);
	if(ret){
		return ret;
	}
	PrintSlider("data", output, 0);
	return HIDCard_PraseData(output);
}

//短格式帧，前半部分数据和后半部分数据相同
static int HIDCard_ShortFrameCheck(HidFrame_T* frame){
	const uint32_t n = HID_CARD_SHORT_FRAME_SIZE/8;
	const uint32_t size = HID_CARD_SHORT_FRAME_SIZE/8 - 1; //减去SOF
	const uint8_t* data = (const uint8_t*)frame->container;
	
	return memcmp(data, data + n, size) == 0;
}

int HIDCard_Decode(HIDProx_T* card, BitSlider_T* bits){
	HidFrame_T frame;
	PrintSlider("manch", bits, 1);
	int ret = HIDCard_Frame_Build(&frame, bits);
	if(ret){
		LOG_ERR("Build frame fail");
		return ret;
	}
	
	enum HidFrameType type = frame.type;
	if(type == HID_FRAME_None){
		LOG_ERR("NONE Frame!");
		return -1;
	}
	
	if(type == HID_FRAME_Short){
		//直接解析3block
		LOG_DBG("SHORT Frame!");
		if(!HIDCard_ShortFrameCheck(&frame)){
			HIDCard_Frame_Init(&card->frame);
			LOG_ERR("Frame check fail!");
			return -2;
		}
	}
	else
	if(type == HID_FRAME_Long){
		LOG_DBG("LONG Frame!");
		if(HIDCard_Frame_Compare(&frame, &card->frame)){
			//缓存
			HIDCard_Frame_Copy(&card->frame, &frame);
			LOG_DBG("save");
			return 1;
		}
		else{
			//解析6block
		}
	}
	
	ret = HIDCard_DecodeFrame(&frame, &card->output);
	if(!ret){
		uint8_t uid[16];
		uint8_t ulen;
		HIDCard_GetUID(&card->output, uid, &ulen);
		LOG_BUF(0, RTT_CTRL_TEXT_BRIGHT_WHITE, "uid", uid, ulen);
	}
	HIDCard_Frame_Init(&card->frame);
	return ret;
}
/*------------------------------------------------------*/
#endif 

static const char* bitStr = 
	"0101010101011010011010011010010110011010101001101001100101100110101001100101010101011010000111010101010101011010011010011010010110011010101001101001100101100110101001100101010101011010";


#if 0
static HIDProx_T hidProx;

static void testGetUID(void){
#if 0
	//UID：02F64E30
	const char* rawBits = "00000010000000000110111101100100111000110000";
#endif 
	//UID：0ECFDA5CE5
	const char* rawBits = "00000011111011001111110110100101110011100101";
	uint32_t buf[16];
	BitSlider_T slider;
	BitSlider_Init(&slider, buf, 16, sizeof(buf) * 8);
	
	const char* p = rawBits;
	while(*p){
		BitSlider_Push(&slider, *p-'0');
		p++;
	}
	
	PrintSlider("rawBits", &slider, 0);
	int ret =  HIDCard_PraseData(&slider);
	if(!ret){
		uint8_t uid[16];
		uint8_t ulen;
		HIDCard_GetUID(&slider, uid, &ulen);
		LOG_BUF(0, RTT_CTRL_TEXT_BRIGHT_WHITE, "uid", uid, ulen);
	}
}
#endif 

TEST_GROUP(HIDProx);


TEST_SETUP(HIDProx)
{
	//BSP_RFID_Enable();
}

TEST_TEAR_DOWN(HIDProx)
{
	BSP_RFID_Disable();
}
static void PrepareBits(BitSlider_T* slider){
	const char* p = bitStr;
	
	while(*p){
		int val = *p - '0';
		BitSlider_Add(slider, val);
		p++;
	}
}

//	int hid_card_decode(BitBuf_T* bitbuf, hid_card_info_t* info);

#if 0
TEST(HIDProx, DecodeBits)
{
	int ret;
	uint32_t buf[16];
	BitSlider_T slider;
	BitSlider_Init(&slider, buf, 16, 0);
	PrepareBits(&slider);
	
	HIDCard_Frame_Init(&hidProx.frameBackup);
	BitSlider_Init(&hidProx.output, hidProx.outputBuffer, sizeof(hidProx.outputBuffer)/sizeof(hidProx.outputBuffer[0]), 0);
	
	testGetUID();

	while(1){
		BSP_Sleep_Ms(500);
		ret = HIDCard_Decode(&hidProx, &slider);
		if(!ret){
			LOG_INF("OK!!");
		}
	}
}
#endif 



IGNORE_TEST(HIDProx, MockReadUID)
{
	int ret;
	HidProxTag_T tag;
	uint32_t buf[16];
	BitSlider_T slider;
	BitSlider_Init(&slider, buf, 16, 0);
	PrepareBits(&slider);
	HIDProx_Init();
	while(1){
		BSP_Sleep_Ms(500);
		HIDProx_Complete(&slider);
		ret = HIDProx_Read(&tag);
		if(!ret){
			LOG_INF("Prox Type=%d", tag.type);
			LOG_BUF(0, RTT_CTRL_TEXT_BRIGHT_WHITE, "uid", tag.uid, tag.ulen);
		}
	}
}

int id_card_get(uint8_t uid[5]);

TEST(HIDProx, ReadUID)
{
	int ret;
	HidProxTag_T tag;
	HIDProx_Init();
	BSP_RFID_Enable();
	while(1){
#if 1
		ret = HIDProx_Read(&tag);
		if(!ret){
			LOG_INF("Prox Type=%d", tag.type);
			LOG_BUF(0, RTT_CTRL_TEXT_BRIGHT_WHITE, "uid", tag.uid, tag.ulen);
		}
#else
		uint8_t uid[5] = {0};
		ret = id_card_get(uid);
		if(!ret){
			LOG_BUF(0, RTT_CTRL_TEXT_BRIGHT_WHITE, "uid", uid, 5);
			BSP_Sleep_Ms(5);
		}
#endif 
	}
}

#if 1

int HIDProx_PraseData(BitSlider_T* output);
void HIDProx_GetUID(BitSlider_T* output, uint8_t* uid, uint8_t* ulen);
static void PushBits(BitSlider_T* slider, const char* strbit){
	const char* p = strbit;
	
	while(*p){
		int val = *p - '0';
		BitSlider_Push(slider, val);
		p++;
	}
}

static void HIDProx_Prepare72(BitSlider_T* output){
	const char *data[6] = {
		[0] = "10010000",		//customer code + '0'
		[1] = "00000001",
		[2] = "00000001",	//1
		[3] = "00000010",	//2
		[4] = "00000011",	//3
		[5] = "00000100",	//4
	};
		
	for(int i = 0; i < 6; i++){
		PushBits(output, data[i]);
	}
}

IGNORE_TEST(HIDProx, Parser72)
{
	uint32_t container[16];
	BitSlider_T output = {.num_bundles = 16, .bundles = container, };
	output.head = output.tail = sizeof(container) * sizeof(uint32_t) - 8;
	HIDProx_Prepare72(&output);
	int ret = HIDProx_PraseData(&output);
	TEST_ASSERT_EQUAL(0, ret);
	uint8_t uid[16];
	uint8_t ulen;
	HIDProx_GetUID(&output, uid, &ulen);
	LOG_BUF(0, RTT_CTRL_TEXT_BRIGHT_WHITE, "uid", uid, ulen);
}

#endif 


